<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js 类与样式绑定详解</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 1000px;
            margin: 0 auto;
            padding: 20px;
            line-height: 1.6;
        }
        h1, h2 {
            color: #4CAF50;
        }
        .demo-section {
            margin: 20px 0;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
            background-color: #f9f9f9;
        }
        .demo-box {
            width: 150px;
            height: 150px;
            margin: 15px 0;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
            border: 2px solid transparent;
        }
        .btn-group {
            margin: 10px 0;
        }
        button {
            background-color: #4CAF50;
            color: white;
            border: none;
            padding: 8px 16px;
            margin: 0 5px;
            cursor: pointer;
            border-radius: 4px;
        }
        button:hover {
            background-color: #45a049;
        }
        input[type="text"] {
            padding: 8px;
            margin: 5px 0;
            border: 1px solid #ddd;
            border-radius: 4px;
            width: 200px;
        }
        input[type="checkbox"] {
            margin: 0 8px;
        }
        code {
            background-color: #eee;
            padding: 2px 4px;
            border-radius: 3px;
            font-family: monospace;
        }
        pre {
            background-color: #f5f5f5;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
            border-left: 4px solid #4CAF50;
        }
        .highlight {
            background-color: #fffacd;
            padding: 2px 4px;
            border-radius: 3px;
        }

        /* 以下是演示用的CSS类 */
        .active {
            background-color: #4CAF50;
            color: white;
        }
        .error {
            background-color: #f44336;
            color: white;
        }
        .warning {
            background-color: #ff9800;
            color: white;
        }
        .border {
            border-color: #2196F3;
            border-style: solid;
        }
        .shadow {
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }
        .rounded {
            border-radius: 15px;
        }
        .large {
            width: 200px;
            height: 200px;
        }
    </style>
    <!-- 引入Vue.js -->
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js"></script>
</head>
<body>
    <h1>Vue.js 类与样式绑定详解</h1>
    <p>本示例演示了Vue中类名(class)和内联样式(style)绑定的所有常见用法，包含完整的代码示例和互动演示。</p>

    <div id="app">
        <!-- 1. 类名绑定的基本用法 -->
        <div class="demo-section">
            <h2>1. 类名绑定基本用法</h2>
            <p>Vue提供了多种方式来动态绑定HTML类名，使其能够根据数据变化而更新。</p>
            
            <h3>1.1 对象语法</h3>
            <p>通过对象语法可以动态地切换类名：</p>
            <pre><code>&lt;div v-bind:class="{ active: isActive, error: hasError }"&gt;&lt;/div&gt;</code></pre>
            
            <div class="demo-box" v-bind:class="{ active: isActive, error: hasError }">
                点击按钮切换类
            </div>
            <div class="btn-group">
                <button @click="isActive = !isActive">切换 active 类</button>
                <button @click="hasError = !hasError">切换 error 类</button>
            </div>

            <h3>1.2 数组语法</h3>
            <p>通过数组语法可以应用多个类：</p>
            <pre><code>&lt;div v-bind:class="[activeClass, errorClass]"&gt;&lt;/div&gt;</code></pre>
            
            <div class="demo-box" v-bind:class="[activeClass, errorClass]">
                数组语法示例
            </div>
            <p>当前类: <span class="highlight">{{ [activeClass, errorClass].filter(Boolean).join(', ') }}</span></p>
            
            <div class="btn-group">
                <button @click="toggleActiveClass">切换 activeClass</button>
                <button @click="toggleErrorClass">切换 errorClass</button>
            </div>

            <h3>1.3 数组语法中的对象</h3>
            <p>可以在数组中使用对象语法：</p>
            <pre><code>&lt;div v-bind:class="[isActive ? 'active' : '', errorClass]"&gt;&lt;/div&gt;</code></pre>
            
            <div class="demo-box" v-bind:class="[isActive ? 'active' : '', errorClass]">
                条件类名示例
            </div>
        </div>

        <!-- 2. 计算属性绑定类 -->
        <div class="demo-section">
            <h2>2. 使用计算属性绑定类</h2>
            <p>当类名逻辑复杂时，推荐使用计算属性：</p>
            
            <pre><code>computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error
    }
  }
}</code></pre>
            
            <div class="demo-box" v-bind:class="classObject">
                计算属性类名
            </div>
            <p>计算结果: <span class="highlight">{{ classObjectText }}</span></p>
            
            <div class="btn-group">
                <button @click="isActive = !isActive">切换 isActive</button>
                <button @click="error = !error">切换 error</button>
            </div>
        </div>

        <!-- 3. 多重类名绑定 -->
        <div class="demo-section">
            <h2>3. 多重类名绑定</h2>
            <p>可以同时使用普通类和动态类：</p>
            
            <pre><code>&lt;div class="demo-box" v-bind:class="{ border: hasBorder, shadow: hasShadow }"&gt;&lt;/div&gt;</code></pre>
            
            <div class="demo-box border" v-bind:class="{ shadow: hasShadow, rounded: isRounded }">
                多重类名绑定
            </div>
            
            <div class="btn-group">
                <label><input type="checkbox" v-model="hasShadow"> 阴影</label>
                <label><input type="checkbox" v-model="isRounded"> 圆角</label>
            </div>
        </div>

        <!-- 4. 内联样式绑定 -->
        <div class="demo-section">
            <h2>4. 内联样式绑定</h2>
            <p>Vue也支持动态绑定内联样式。</p>
            
            <h3>4.1 对象语法</h3>
            <pre><code>&lt;div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"&gt;&lt;/div&gt;</code></pre>
            
            <div class="demo-box" v-bind:style="{ backgroundColor: bgColor, color: textColor, fontSize: fontSize + 'px' }">
                内联样式对象语法
            </div>
            
            <div>
                <p>背景颜色: <input type="text" v-model="bgColor" placeholder="例如: #ff0000"></p>
                <p>文字颜色: <input type="text" v-model="textColor" placeholder="例如: #ffffff"></p>
                <p>字体大小: <input type="range" v-model.number="fontSize" min="12" max="36">{{ fontSize }}px</p>
            </div>

            <h3>4.2 直接绑定样式对象</h3>
            <pre><code>&lt;div v-bind:style="styleObject"&gt;&lt;/div&gt;</code></pre>
            
            <div class="demo-box" v-bind:style="styleObject">
                样式对象绑定
            </div>
            
            <button @click="toggleStyle">切换样式对象</button>

            <h3>4.3 数组语法</h3>
            <p>可以将多个样式对象应用到同一个元素：</p>
            <pre><code>&lt;div v-bind:style="[baseStyles, overridingStyles]"&gt;&lt;/div&gt;</code></pre>
            
            <div class="demo-box" v-bind:style="[baseStyles, overridingStyles]">
                样式数组语法
            </div>
        </div>

        <!-- 5. 实战示例：可配置的提示框 -->
        <div class="demo-section">
            <h2>5. 实战示例：可配置的提示框</h2>
            <p>结合类名和样式绑定创建一个可配置的提示框组件：</p>
            
            <div class="alert" v-bind:class="alertClass" v-bind:style="alertStyle">
                <strong>{{ alertTitle }}</strong>
                <p>{{ alertMessage }}</p>
            </div>
            
            <div>
                <p>提示类型: 
                    <button @click="setAlertType('success')">成功</button>
                    <button @click="setAlertType('error')">错误</button>
                    <button @click="setAlertType('warning')">警告</button>
                </p>
                <p>宽度: <input type="range" v-model.number="alertWidth" min="200" max="600">{{ alertWidth }}px</p>
                <p>提示标题: <input type="text" v-model="alertTitle"></p>
                <p>提示内容: <input type="text" v-model="alertMessage"></p>
            </div>
        </div>

        <!-- 6. 总结 -->
        <div class="demo-section">
            <h2>6. 总结</h2>
            <h3>类名绑定</h3>
            <ul>
                <li><code>v-bind:class="{ active: isActive }"</code> - 对象语法，动态切换类</li>
                <li><code>v-bind:class="[activeClass, errorClass]"</code> - 数组语法，应用多个类</li>
                <li><code>v-bind:class="classObject"</code> - 绑定计算属性返回的类对象</li>
                <li><code>v-bind:class="[isActive ? 'active' : '', errorClass]"</code> - 数组中的条件表达式</li>
            </ul>
            
            <h3>样式绑定</h3>
            <ul>
                <li><code>v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"</code> - 内联样式对象</li>
                <li><code>v-bind:style="styleObject"</code> - 绑定样式对象</li>
                <li><code>v-bind:style="[baseStyles, overridingStyles]"</code> - 样式数组，合并多个样式对象</li>
            </ul>
            
            <h3>最佳实践</h3>
            <ul>
                <li>当类名逻辑复杂时，优先使用计算属性</li>
                <li>对于可复用的样式，定义为CSS类而不是内联样式</li>
                <li>使用kebab-case（短横线分隔）定义CSS属性名</li>
                <li>利用Vue的响应式特性，通过数据驱动UI变化</li>
            </ul>
        </div>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
                // 基本类名绑定
                isActive: false,
                hasError: false,
                activeClass: 'active',
                errorClass: '',
                
                // 计算属性类名
                error: false,
                
                // 多重类名
                hasBorder: true,
                hasShadow: false,
                isRounded: false,
                
                // 内联样式
                bgColor: '#4CAF50',
                textColor: '#ffffff',
                fontSize: 16,
                styleObject: {
                    backgroundColor: '#2196F3',
                    color: '#ffffff',
                    fontWeight: 'bold'
                },
                baseStyles: {
                    padding: '20px',
                    textAlign: 'center'
                },
                overridingStyles: {
                    backgroundColor: '#9C27B0',
                    color: '#ffffff'
                },
                
                // 实战示例
                alertType: 'success',
                alertWidth: 400,
                alertTitle: '成功提示',
                alertMessage: '操作已成功完成！'
            },
            methods: {
                toggleActiveClass: function() {
                    this.activeClass = this.activeClass === 'active' ? '' : 'active';
                },
                toggleErrorClass: function() {
                    this.errorClass = this.errorClass === 'error' ? '' : 'error';
                },
                toggleStyle: function() {
                    if (this.styleObject.backgroundColor === '#2196F3') {
                        this.styleObject = {
                            backgroundColor: '#FF5722',
                            color: '#ffffff',
                            fontWeight: 'normal'
                        };
                    } else {
                        this.styleObject = {
                            backgroundColor: '#2196F3',
                            color: '#ffffff',
                            fontWeight: 'bold'
                        };
                    }
                },
                setAlertType: function(type) {
                    this.alertType = type;
                    // 根据类型更新提示内容
                    if (type === 'success') {
                        this.alertTitle = '成功提示';
                        this.alertMessage = '操作已成功完成！';
                    } else if (type === 'error') {
                        this.alertTitle = '错误提示';
                        this.alertMessage = '操作失败，请重试！';
                    } else if (type === 'warning') {
                        this.alertTitle = '警告提示';
                        this.alertMessage = '请确认您的操作！';
                    }
                }
            },
            computed: {
                classObject: function() {
                    return {
                        active: this.isActive && !this.error,
                        error: this.error
                    };
                },
                classObjectText: function() {
                    const classes = [];
                    if (this.isActive && !this.error) classes.push('active');
                    if (this.error) classes.push('error');
                    return classes.join(', ') || '无';
                },
                // 实战示例的计算属性
                alertClass: function() {
                    return {
                        'alert-success': this.alertType === 'success',
                        'alert-error': this.alertType === 'error',
                        'alert-warning': this.alertType === 'warning'
                    };
                },
                alertStyle: function() {
                    let bgColor = '#4CAF50';
                    let borderColor = '#388E3C';
                    
                    if (this.alertType === 'error') {
                        bgColor = '#F44336';
                        borderColor = '#D32F2F';
                    } else if (this.alertType === 'warning') {
                        bgColor = '#FF9800';
                        borderColor = '#F57C00';
                    }
                    
                    return {
                        width: this.alertWidth + 'px',
                        backgroundColor: bgColor,
                        color: '#ffffff',
                        padding: '15px',
                        border: '2px solid ' + borderColor,
                        borderRadius: '5px',
                        margin: '10px 0'
                    };
                }
            }
        });
    </script>
    
    <style>
        /* 提示框样式 */
        .alert {
            transition: all 0.3s ease;
        }
        .alert strong {
            font-size: 18px;
            display: block;
            margin-bottom: 8px;
        }
        .alert p {
            margin: 0;
        }
    </style>
</body>
</html>